package com.gitee.ed.common.scanner;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ClassUtil;

import java.util.*;

/**
 * 类扫描器
 *
 * @author hongda.li
 */
public class ClassScanner {
    /**
     * 初始化状态
     */
    private static final int INIT = 0;
    /**
     * 开始扫描状态
     */
    private static final int SCANNING = 1;
    /**
     * 停止状态
     */
    private static final int STOP = -1;
    /**
     * 扫描状态标记
     */
    private int status;
    /**
     * 类扫描结果
     */
    private final Set<Class<?>> classes = new HashSet<>();
    /**
     * 类过滤器
     */
    private final List<ClassFilter> filters = new ArrayList<>();
    /**
     * 类处理器
     */
    private final List<ClassProcessor> processors = new ArrayList<>();

    /**
     * 创建一个类扫描器
     */
    public ClassScanner() {
        this.status = INIT;
    }

    /**
     * 添加一个类过滤器
     *
     * @param filter 类过滤器
     * @return 链式调用
     */
    public ClassScanner addFilter(ClassFilter filter) {
        Assert.isTrue(this.status == INIT, "Unable to add the filter in scanning state");
        Objects.requireNonNull(filter);
        filters.add(filter);
        return this;
    }

    /**
     * 添加一个类处理器
     * 类处理器可以执行中断扫描或递归扫描操作
     * 也可以处理中间态的类
     *
     * @param processor 类处理器
     * @return 链式调用
     */
    public ClassScanner addProcessor(ClassProcessor processor) {
        Assert.isTrue(this.status == INIT, "Unable to add the processor in scanning state");
        Objects.requireNonNull(processor);
        processors.add(processor);
        return this;
    }

    /**
     * 扫描指定类所在包下的所有类且包含此类
     *
     * @param clazz 指定类
     * @return 链式调用
     */
    public ClassScanner scan(Class<?> clazz) {
        return this.scan(ClassUtil.getPackage(clazz));
    }

    /**
     * 扫描指定包下的所有类
     *
     * @param packageName 包名称
     * @return 链式调用
     */
    public ClassScanner scan(String packageName) {
        // 标记为正在扫描状态
        this.status = SCANNING;

        // 中间态类集合，此集合中的类暂未被添加到最终扫描集中
        final Set<Class<?>> scanned = ClassUtil.scanPackage(packageName, clz -> {
            // 执行类过滤器
            for (ClassFilter filter : this.filters) {
                // 被禁止的类不会被扫描到中间态
                if (!filter.doFilter(clz)) {
                    return false;
                }
            }
            return true;
        });

        if (CollUtil.isEmpty(scanned)) {
            return this;
        }

        // 依次处理每一个被扫描的类
        for (Class<?> clazz : scanned) {
            // 将中间态类依次添加到最终结果集
            this.classes.add(clazz);

            for (ClassProcessor processor : this.processors) {
                // 由自定义类处理器处理
                processor.process(clazz, this);

                // 若自定义类处理器设置了终止扫描标记则执行中断
                if (STOP == this.status) {
                    return this;
                }
            }
        }

        return this;
    }

    /**
     * 设置终止扫描
     *
     * @return 链式调用
     */
    public ClassScanner stop() {
        this.status = STOP;
        return this;
    }

    /**
     * 获取最终扫描的类集合
     *
     * @return 最终态类集合
     */
    public Set<Class<?>> getScanned() {
        return classes;
    }
}
